home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xlock / life.c < prev    next >
C/C++ Source or Header  |  1995-05-09  |  14KB  |  613 lines

  1. #ifndef lint
  2. static char sccsid[] = "@(#)life.c    23.6 91/05/24 XLOCK";
  3. #endif
  4. /*-
  5.  * life.c - Conway's game of Life for xlock, the X Window System lockscreen.
  6.  *
  7.  * Copyright (c) 1991 by Patrick J. Naughton.
  8.  *
  9.  * See xlock.c for copying information.
  10.  *
  11.  * Revision History:
  12.  * 24-May-91: Added wraparound code from johnson@bugs.comm.mot.com.
  13.  *          Made old cells stay blue.
  14.  *          Made batchcount control the number of generations till restart.
  15.  * 29-Jul-90: support for multiple screens.
  16.  * 07-Feb-90: remove bogus semi-colon after #include line.
  17.  * 15-Dec-89: Fix for proper skipping of {White,Black}Pixel() in colors.
  18.  * 08-Oct-89: Moved seconds() to an extern.
  19.  * 20-Sep-89: Written (life algorithm courtesy of Jim Graham, flar@sun.com).
  20.  */
  21.  
  22. #include "xlock.h"
  23. #include "lifeicon.bit"
  24.  
  25. static XImage logo = {
  26.     0, 0,            /* width, height */
  27.     0, XYBitmap, 0,        /* xoffset, format, data */
  28.     LSBFirst, 8,        /* byte-order, bitmap-unit */
  29.     LSBFirst, 8, 1        /* bitmap-bit-order, bitmap-pad, depth */
  30. };
  31. #define min(a, b) ((a)<(b)?(a):(b))
  32. #define    MAXROWS    155
  33. #define MAXCOLS    144
  34. #define TIMEOUT 30
  35.  
  36. typedef struct {
  37.     int         pixelmode;
  38.     int         xs;
  39.     int         ys;
  40.     int         xb;
  41.     int         yb;
  42.     int         generation;
  43.     long        shooterTime;
  44.     int         nrows;
  45.     int         ncols;
  46.     int         width;
  47.     int         height;
  48.     unsigned char buffer[(MAXROWS + 2) * (MAXCOLS + 2) + 2];
  49.     unsigned char tempbuf[MAXCOLS * 2];
  50.     unsigned char lastbuf[MAXCOLS];
  51.     unsigned char agebuf[(MAXROWS + 2) * (MAXCOLS + 2)];
  52. }           lifestruct;
  53.  
  54. static lifestruct lifes[MAXSCREENS];
  55. static int  icon_width, icon_height;
  56.  
  57. /* Buffer stores the data for each cell. Each cell is stored as
  58.  * 8 bits representing the presence of a critter in each of it's
  59.  * surrounding 8 cells. There is an empty row and column around
  60.  * the whole array to allow stores without bounds checking as well
  61.  * as an extra row at the end for the fetches into tempbuf.
  62.  *
  63.  * Tempbuf stores the data for the next two rows so that we know
  64.  * the state of those critter before he was modified by the fate
  65.  * of the critters that have already been processed.
  66.  *
  67.  * Agebuf stores the age of each critter.
  68.  */
  69.  
  70. #define    UPLT    0x01
  71. #define UP    0x02
  72. #define UPRT    0x04
  73. #define LT    0x08
  74. #define RT    0x10
  75. #define DNLT    0x20
  76. #define DN    0x40
  77. #define DNRT    0x80
  78.  
  79. /* Fates is a lookup table for the fate of a critter. The 256
  80.  * entries represent the 256 possible combinations of the 8
  81.  * neighbor cells. Each entry is one of BIRTH (create a cell
  82.  * or leave one alive), SAME (leave the cell alive or dead),
  83.  * or DEATH (kill anything in the cell).
  84.  */
  85. #define BIRTH    0
  86. #define SAME    1
  87. #define DEATH    2
  88. static unsigned char fates[256];
  89. static int  initialized = 0;
  90.  
  91. static int  patterns[][128] = {
  92.     {                /* EIGHT */
  93.     -3, -3, -2, -3, -1, -3,
  94.     -3, -2, -2, -2, -1, -2,
  95.     -3, -1, -2, -1, -1, -1,
  96.     0, 0, 1, 0, 2, 0,
  97.     0, 1, 1, 1, 2, 1,
  98.     0, 2, 1, 2, 2, 2,
  99.     99
  100.     },
  101.     {                /* PULSAR */
  102.     1, 1, 2, 1, 3, 1, 4, 1, 5, 1,
  103.     1, 2, 5, 2,
  104.     99
  105.     },
  106.     {                /* BARBER */
  107.     -7, -7, -6, -7,
  108.     -7, -6, -5, -6,
  109.     -5, -4, -3, -4,
  110.     -3, -2, -1, -2,
  111.     -1, 0, 1, 0,
  112.     1, 2, 3, 2,
  113.     3, 4, 5, 4,
  114.     4, 5, 5, 5,
  115.     99
  116.     },
  117.     {                /* HERTZ */
  118.     -2, -6, -1, -6,
  119.     -2, -5, -1, -5,
  120.     -7, -3, -6, -3, -2, -3, -1, -3, 0, -3, 1, -3, 5, -3, 6, -3,
  121.     -7, -2, -5, -2, -3, -2, 2, -2, 4, -2, 6, -2,
  122.     -5, -1, -3, -1, -2, -1, 2, -1, 4, -1,
  123.     -7, 0, -5, 0, -3, 0, 2, 0, 4, 0, 6, 0,
  124.     -7, 1, -6, 1, -2, 1, -1, 1, 0, 1, 1, 1, 5, 1, 6, 1,
  125.     -2, 3, -1, 3,
  126.     -2, 4, -1, 4,
  127.     99
  128.     },
  129.     {                /* TUMBLER */
  130.     -6, -6, -5, -6, 6, -6, 7, -6,
  131.     -6, -5, -5, -5, 6, -5, 7, -5,
  132.     -5, 5, 6, 5,
  133.     -7, 6, -5, 6, 6, 6, 8, 6,
  134.     -7, 7, -5, 7, 6, 7, 8, 7,
  135.     -7, 8, -6, 8, 7, 8, 8, 8,
  136.     99
  137.     },
  138.     {                /* PERIOD4 */
  139.     -5, -8, -4, -8,
  140.     -7, -7, -5, -7,
  141.     -8, -6, -2, -6,
  142.     -7, -5, -3, -5, -2, -5,
  143.     -5, -3, -3, -3,
  144.     -4, -2,
  145.     99
  146.     },
  147.     {                /* PERIOD5 */
  148.     -5, -8, -4, -8,
  149.     -6, -7, -3, -7,
  150.     -7, -6, -2, -6,
  151.     -8, -5, -1, -5,
  152.     -8, -4, -1, -4,
  153.     -7, -3, -2, -3,
  154.     -6, -2, -3, -2,
  155.     -5, -1, -4, -1,
  156.     99
  157.     },
  158.     {                /* PERIOD6 */
  159.     -4, -8, -3, -8,
  160.     -8, -7, -7, -7, -5, -7,
  161.     -8, -6, -7, -6, -4, -6, -1, -6,
  162.     -3, -5, -1, -5,
  163.     -2, -4,
  164.     -3, -2, -2, -2,
  165.     -3, -1, -2, -1,
  166.     99
  167.     },
  168.     {                /* PINWHEEL */
  169.     -4, -8, -3, -8,
  170.     -4, -7, -3, -7,
  171.     -4, -5, -3, -5, -2, -5, -1, -5,
  172.     -5, -4, -3, -4, 0, -4, 2, -4, 3, -4,
  173.     -5, -3, -1, -3, 0, -3, 2, -3, 3, -3,
  174.     -8, -2, -7, -2, -5, -2, -2, -2, 0, -2,
  175.     -8, -1, -7, -1, -5, -1, 0, -1,
  176.     -4, 0, -3, 0, -2, 0, -1, 0,
  177.     -2, 2, -1, 2,
  178.     -2, 3, -1, 3,
  179.     99
  180.     },
  181.     {                /* ] */
  182.     -1, -1, 0, -1, 1, -1,
  183.     0, 0, 1, 0,
  184.     -1, 1, 0, 1, 1, 1,
  185.     99
  186.     },
  187.     {                /* cc: */
  188.     -3, -1, -2, -1, -1, -1, 1, -1, 2, -1, 3, -1,
  189.     -3, 0, -2, 0, 1, 0, 2, 0,
  190.     -3, 1, -2, 1, -1, 1, 1, 1, 2, 1, 3, 1,
  191.     99
  192.     },
  193.     {                /* DOLBY */
  194.     -3, -1, -2, -1, -1, -1, 1, -1, 2, -1, 3, -1,
  195.     -3, 0, -2, 0, 2, 0, 3, 0,
  196.     -3, 1, -2, 1, -1, 1, 1, 1, 2, 1, 3, 1,
  197.     99
  198.     },
  199.     {                /* HORIZON */
  200.     -15, 0, -14, 0, -13, 0, -12, 0, -11, 0,
  201.     -10, 0, -9, 0, -8, 0, -7, 0, -6, 0,
  202.     -5, 0, -4, 0, -3, 0, -2, 0, -1, 0,
  203.     4, 0, 3, 0, 2, 0, 1, 0, 0, 0,
  204.     9, 0, 8, 0, 7, 0, 6, 0, 5, 0,
  205.     14, 0, 13, 0, 12, 0, 11, 0, 10, 0,
  206.     99
  207.     },
  208.     {                /* SHEAR */
  209.     -7, -2, -6, -2, -5, -2, -4, -2, -3, -2,
  210.     -2, -2, -1, -2, 0, -2, 1, -2, 2, -2,
  211.     -5, -1, -4, -1, -3, -1, -2, -1, -1, -1,
  212.     0, -1, 1, -1, 2, -1, 3, -1, 4, -1,
  213.     -3, 0, -2, 0, -1, 0, 0, 0, 1, 0,
  214.     2, 0, 3, 0, 4, 0, 5, 0, 6, 0,
  215.     -10, 1, -9, 1, -8, 1, -7, 1, -6, 1,
  216.     -5, 1, -4, 1, -3, 1, -2, 1, -1, 1,
  217.     -10, 2, -9, 2, -8, 2, -7, 2, -6, 2,
  218.     -5, 2, -4, 2, -3, 2, -2, 2, -1, 2,
  219.     99
  220.     },
  221.     {                /* VERTIGO */
  222.     0, -7,
  223.     0, -6,
  224.     0, -5,
  225.     0, -4,
  226.     0, -3,
  227.     0, -2,
  228.     0, -1,
  229.     0, 0,
  230.     0, 7,
  231.     0, 6,
  232.     0, 5,
  233.     0, 4,
  234.     0, 3,
  235.     0, 2,
  236.     0, 1,
  237.     99
  238.     },
  239.     {                /* CROSSBAR */
  240.     -5, 0, -4, 0, -3, 0, -2, 0, -1, 0, 4, 0, 3, 0, 2, 0, 1, 0, 0, 0,
  241.     99
  242.     },
  243.     {                /* GOALPOSTS */
  244.     -8, -7, 8, -7,
  245.     -8, -6, 8, -6,
  246.     -8, -5, 8, -5,
  247.     -8, -4, 8, -4,
  248.     -8, -3, 8, -3,
  249.     -8, -2, 8, -2,
  250.     -8, -1, 8, -1,
  251.     -8, 0, 8, 0,
  252.     -8, 1, 8, 1,
  253.     -8, 2, 8, 2,
  254.     -8, 3, 8, 3,
  255.     -8, 4, 8, 4,
  256.     -8, 5, 8, 5,
  257.     -8, 6, 8, 6,
  258.     -8, 7, 8, 7,
  259.     99
  260.     },
  261.     {                /* \ */
  262.     -8, -8, -7, -8,
  263.     -7, -7, -6, -7,
  264.     -6, -6, -5, -6,
  265.     -5, -5, -4, -5,
  266.     -4, -4, -3, -4,
  267.     -3, -3, -2, -3,
  268.     -2, -2, -1, -2,
  269.     -1, -1, 0, -1,
  270.     0, 0, 1, 0,
  271.     1, 1, 2, 1,
  272.     2, 2, 3, 2,
  273.     3, 3, 4, 3,
  274.     4, 4, 5, 4,
  275.     5, 5, 6, 5,
  276.     6, 6, 7, 6,
  277.     7, 7, 8, 7,
  278.     99
  279.     },
  280.     {                /* LABYRINTH */
  281.     -4, -4, -3, -4, -2, -4, -1, -4, 0, -4, 1, -4, 2, -4, 3, -4, 4, -4,
  282.     -4, -3, 0, -3, 4, -3,
  283.     -4, -2, -2, -2, -1, -2, 0, -2, 1, -2, 2, -2, 4, -2,
  284.     -4, -1, -2, -1, 2, -1, 4, -1,
  285.     -4, 0, -2, 0, -1, 0, 0, 0, 1, 0, 2, 0, 4, 0,
  286.     -4, 1, -2, 1, 2, 1, 4, 1,
  287.     -4, 2, -2, 2, -1, 2, 0, 2, 1, 2, 2, 2, 4, 2,
  288.     -4, 3, 0, 3, 4, 3,
  289.     -4, 4, -3, 4, -2, 4, -1, 4, 0, 4, 1, 4, 2, 4, 3, 4, 4, 4,
  290.     99
  291.     }
  292. };
  293.  
  294. #define NPATS    (sizeof patterns / sizeof patterns[0])
  295.  
  296.  
  297. static void
  298. drawcell(win, row, col)
  299.     Window      win;
  300.     int         row, col;
  301. {
  302.     lifestruct *lp = &lifes[screen];
  303.  
  304.     XSetForeground(dsp, Scr[screen].gc, WhitePixel(dsp, screen));
  305.     if (!mono && Scr[screen].npixels > 2) {
  306.     unsigned char *loc = lp->buffer + ((row + 1) * (lp->ncols + 2)) + col + 1;
  307.     unsigned char *ageptr = lp->agebuf + (loc - lp->buffer);
  308.     unsigned char age = *ageptr;
  309.  
  310.     /* if we aren't up to blue yet, then keep aging the cell. */
  311.     if (age < Scr[screen].npixels * 0.7)
  312.         ++age;
  313.  
  314.     XSetForeground(dsp, Scr[screen].gc, Scr[screen].pixels[age]);
  315.     *ageptr = age;
  316.     }
  317.     if (lp->pixelmode)
  318.     XFillRectangle(dsp, win, Scr[screen].gc,
  319.            lp->xb + lp->xs * col, lp->yb + lp->ys * row, lp->xs, lp->ys);
  320.     else
  321.     XPutImage(dsp, win, Scr[screen].gc, &logo,
  322.           0, 0, lp->xb + lp->xs * col, lp->yb + lp->ys * row,
  323.           icon_width, icon_height);
  324. }
  325.  
  326.  
  327. static void
  328. erasecell(win, row, col)
  329.     Window      win;
  330.     int         row, col;
  331. {
  332.     lifestruct *lp = &lifes[screen];
  333.     XSetForeground(dsp, Scr[screen].gc, BlackPixel(dsp, screen));
  334.     XFillRectangle(dsp, win, Scr[screen].gc,
  335.            lp->xb + lp->xs * col, lp->yb + lp->ys * row, lp->xs, lp->ys);
  336. }
  337.  
  338.  
  339. static void
  340. spawn(loc)
  341.     unsigned char *loc;
  342. {
  343.     lifestruct *lp = &lifes[screen];
  344.     unsigned char *ulloc, *ucloc, *urloc, *clloc, *crloc, *llloc, *lcloc, *lrloc,
  345.                *arloc;
  346.     int         off, row, col, lastrow;
  347.  
  348.     lastrow = (lp->nrows) * (lp->ncols + 2);
  349.     off = loc - lp->buffer;
  350.     col = off % (lp->ncols + 2);
  351.     row = (off - col) / (lp->ncols + 2);
  352.     ulloc = loc - lp->ncols - 3;
  353.     ucloc = loc - lp->ncols - 2;
  354.     urloc = loc - lp->ncols - 1;
  355.     clloc = loc - 1;
  356.     crloc = loc + 1;
  357.     arloc = loc + 1;
  358.     llloc = loc + lp->ncols + 1;
  359.     lcloc = loc + lp->ncols + 2;
  360.     lrloc = loc + lp->ncols + 3;
  361.     if (row == 1) {
  362.     ulloc += lastrow;
  363.     ucloc += lastrow;
  364.     urloc += lastrow;
  365.     }
  366.     if (row == lp->nrows) {
  367.     llloc -= lastrow;
  368.     lcloc -= lastrow;
  369.     lrloc -= lastrow;
  370.     }
  371.     if (col == 1) {
  372.     ulloc += lp->ncols;
  373.     clloc += lp->ncols;
  374.     llloc += lp->ncols;
  375.     }
  376.     if (col == lp->ncols) {
  377.     urloc -= lp->ncols;
  378.     crloc -= lp->ncols;
  379.     lrloc -= lp->ncols;
  380.     }
  381.     *ulloc |= UPLT;
  382.     *ucloc |= UP;
  383.     *urloc |= UPRT;
  384.     *clloc |= LT;
  385.     *crloc |= RT;
  386.     *arloc |= RT;
  387.     *llloc |= DNLT;
  388.     *lcloc |= DN;
  389.     *lrloc |= DNRT;
  390.  
  391.     *(lp->agebuf + (loc - lp->buffer)) = 0;
  392. }
  393.  
  394.  
  395. static void
  396. kill(loc)
  397.     unsigned char *loc;
  398. {
  399.     lifestruct *lp = &lifes[screen];
  400.  
  401.     unsigned char *ulloc, *ucloc, *urloc, *clloc, *crloc, *llloc, *lcloc,
  402.                *lrloc, *arloc;
  403.     int         off, row, col, lastrow;
  404.  
  405.     lastrow = (lp->nrows) * (lp->ncols + 2);
  406.     off = loc - lp->buffer;
  407.     row = off / (lp->ncols + 2);
  408.     col = off % (lp->ncols + 2);
  409.     row = (off - col) / (lp->ncols + 2);
  410.     ulloc = loc - lp->ncols - 3;
  411.     ucloc = loc - lp->ncols - 2;
  412.     urloc = loc - lp->ncols - 1;
  413.     clloc = loc - 1;
  414.     crloc = loc + 1;
  415.     arloc = loc + 1;
  416.     llloc = loc + lp->ncols + 1;
  417.     lcloc = loc + lp->ncols + 2;
  418.     lrloc = loc + lp->ncols + 3;
  419.     if (row == 1) {
  420.     ulloc += lastrow;
  421.     ucloc += lastrow;
  422.     urloc += lastrow;
  423.     }
  424.     if (row == lp->nrows) {
  425.     llloc -= lastrow;
  426.     lcloc -= lastrow;
  427.     lrloc -= lastrow;
  428.     }
  429.     if (col == 1) {
  430.     ulloc += lp->ncols;
  431.     clloc += lp->ncols;
  432.     llloc += lp->ncols;
  433.     }
  434.     if (col == lp->ncols) {
  435.     urloc -= lp->ncols;
  436.     crloc -= lp->ncols;
  437.     lrloc -= lp->ncols;
  438.     }
  439.     *ulloc &= ~UPLT;
  440.     *ucloc &= ~UP;
  441.     *urloc &= ~UPRT;
  442.     *clloc &= ~LT;
  443.     *crloc &= ~RT;
  444.     *arloc &= ~RT;
  445.     *llloc &= ~DNLT;
  446.     *lcloc &= ~DN;
  447.     *lrloc &= ~DNRT;
  448. }
  449.  
  450.  
  451. static void
  452. setcell(win, row, col)
  453.     Window      win;
  454.     int         row;
  455.     int         col;
  456. {
  457.     lifestruct *lp = &lifes[screen];
  458.     unsigned char *loc;
  459.  
  460.     loc = lp->buffer + ((row + 1) * (lp->ncols + 2)) + col + 1;
  461.     spawn(loc);
  462.     drawcell(win, row, col);
  463. }
  464.  
  465.  
  466. static void
  467. init_fates()
  468. {
  469.     int         i, bits, neighbors;
  470.  
  471.     for (i = 0; i < 256; i++) {
  472.     neighbors = 0;
  473.     for (bits = i; bits; bits &= (bits - 1))
  474.         neighbors++;
  475.     if (neighbors == 3)
  476.         fates[i] = BIRTH;
  477.     else if (neighbors == 2)
  478.         fates[i] = SAME;
  479.     else
  480.         fates[i] = DEATH;
  481.     }
  482. }
  483.  
  484.  
  485. void
  486. initlife(win)
  487.     Window      win;
  488. {
  489.     int         row, col;
  490.     int        *patptr;
  491.     XWindowAttributes xgwa;
  492.     lifestruct *lp = &lifes[screen];
  493.  
  494.     lp->generation = 0;
  495.     lp->shooterTime = seconds();
  496.     icon_width = lifeicon_width;
  497.     icon_height = lifeicon_height;
  498.  
  499.     if (!initialized) {
  500.     initialized = 1;
  501.     init_fates();
  502.     logo.data = (char *) lifeicon_bits;
  503.     logo.width = icon_width;
  504.     logo.height = icon_height;
  505.     logo.bytes_per_line = (icon_width + 7) / 8;
  506.     }
  507.     XGetWindowAttributes(dsp, win, &xgwa);
  508.     lp->width = xgwa.width;
  509.     lp->height = xgwa.height;
  510.     lp->pixelmode = (lp->width < 4 * icon_width);
  511.     if (lp->pixelmode) {
  512.     lp->ncols = 32;
  513.     lp->nrows = 32;
  514.     } else {
  515.     lp->ncols = min(lp->width / icon_width, MAXCOLS);
  516.     lp->nrows = min(lp->height / icon_height, MAXROWS);
  517.     }
  518.     lp->xs = lp->width / lp->ncols;
  519.     lp->ys = lp->height / lp->nrows;
  520.     lp->xb = (lp->width - lp->xs * lp->ncols) / 2;
  521.     lp->yb = (lp->height - lp->ys * lp->nrows) / 2;
  522.  
  523.     XSetForeground(dsp, Scr[screen].gc, BlackPixel(dsp, screen));
  524.     XFillRectangle(dsp, win, Scr[screen].gc, 0, 0, lp->width, lp->height);
  525.  
  526.     bzero(lp->buffer, sizeof(lp->buffer));
  527.     patptr = &patterns[random() % NPATS][0];
  528.     while ((col = *patptr++) != 99) {
  529.     row = *patptr++;
  530.     col += lp->ncols / 2;
  531.     row += lp->nrows / 2;
  532.     setcell(win, row, col);
  533.     }
  534. }
  535.  
  536.  
  537. void
  538. drawlife(win)
  539.     Window      win;
  540. {
  541.     unsigned char *loc, *temploc, *lastloc;
  542.     int         row, col;
  543.     unsigned char fate;
  544.     lifestruct *lp = &lifes[screen];
  545.  
  546.     loc = lp->buffer + lp->ncols + 2 + 1;
  547.     temploc = lp->tempbuf;
  548.     /* copy the first 2 rows to the tempbuf */
  549.     bcopy(loc, temploc, lp->ncols);
  550.     bcopy(loc + lp->ncols + 2, temploc + lp->ncols, lp->ncols);
  551.  
  552.     lastloc = lp->lastbuf;
  553.     /* copy the last row to another buffer for wraparound */
  554.     bcopy(loc + ((lp->nrows - 1) * (lp->ncols + 2)), lastloc, lp->ncols);
  555.  
  556.     for (row = 0; row < lp->nrows; ++row) {
  557.     for (col = 0; col < lp->ncols; ++col) {
  558.         fate = fates[*temploc];
  559.         *temploc = (row == (lp->nrows - 3)) ?
  560.         *(lastloc + col) :
  561.         *(loc + (lp->ncols + 2) * 2);
  562.         switch (fate) {
  563.         case BIRTH:
  564.         if (!(*(loc + 1) & RT)) {
  565.             spawn(loc);
  566.         }
  567.         /* NO BREAK */
  568.         case SAME:
  569.         if (*(loc + 1) & RT) {
  570.             drawcell(win, row, col);
  571.         }
  572.         break;
  573.         case DEATH:
  574.         if (*(loc + 1) & RT) {
  575.             kill(loc);
  576.             erasecell(win, row, col);
  577.         }
  578.         break;
  579.         }
  580.         loc++;
  581.         temploc++;
  582.     }
  583.     loc += 2;
  584.     if (temploc >= lp->tempbuf + lp->ncols * 2)
  585.         temploc = lp->tempbuf;
  586.     }
  587.  
  588.     if (++lp->generation > batchcount)
  589.     initlife(win);
  590.  
  591.     /*
  592.      * generate a randomized shooter aimed roughly toward the center of the
  593.      * screen after timeout.
  594.      */
  595.  
  596.     if (seconds() - lp->shooterTime > TIMEOUT) {
  597.     int         hsp = random() % (lp->ncols - 5) + 3;
  598.     int         vsp = random() % (lp->nrows - 5) + 3;
  599.     int         hoff = 1;
  600.     int         voff = 1;
  601.     if (vsp > lp->nrows / 2)
  602.         voff = -1;
  603.     if (hsp > lp->ncols / 2)
  604.         hoff = -1;
  605.     setcell(win, vsp + 0 * voff, hsp + 2 * hoff);
  606.     setcell(win, vsp + 1 * voff, hsp + 2 * hoff);
  607.     setcell(win, vsp + 2 * voff, hsp + 2 * hoff);
  608.     setcell(win, vsp + 2 * voff, hsp + 1 * hoff);
  609.     setcell(win, vsp + 1 * voff, hsp + 0 * hoff);
  610.     lp->shooterTime = seconds();
  611.     }
  612. }
  613.